﻿using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Threading;
using ParallelRuntimeLibrary.Internal;


namespace ParallelRuntimeLibrary
{
    public class Task
    {
        #region Fields
        
        protected string mIdentity;
        internal TaskType mType;
        protected ManualResetEvent mFinished;
        protected TaskCreationOptions mOption;
        protected TaskStatus mStatus;

        internal List<Task> mChildren;

        internal object mState;
        protected Action<object> mCallBackTarget;

        protected object SyncObject;

        #endregion

        /*/////////////////////////////////////////////////////////////////////////////*/

        #region Properties

        public string Identity
        {
            get { return mIdentity; }
        }

        internal TaskType Type
        {
            get { return mType; }
        }

        internal ManualResetEvent FinishedEvent
        {
            get { return mFinished; }
        }

        public TaskCreationOptions Option
        {
            get { return mOption; }
        }

        public TaskStatus Status
        {
            get { return mStatus; }
            internal set { mStatus = value; }
        }

        internal object State
        {
            get { return mState; }
        }

        internal Action<object> CallBackTarget
        {
            get { return mCallBackTarget; }
        }

        #endregion

        /*////////////////////////////////////////////////////////////////////////////////////////////////////*/

        #region Synchronize Tsak Access

        internal bool TryEnter()
        {
            return Monitor.TryEnter(SyncObject, 0);
        }

        internal bool TryEnterIfTaskIsQueued()
        {
            if (Monitor.TryEnter(SyncObject, 0))
            {
                if (mStatus == TaskStatus.Queued) 
                    return true;
                else
                {
                    Monitor.Exit(SyncObject);
                    return false;
                }
            }
            else
                return false;
        }

        internal bool TryEnterAndChangeStatusAndExit(TaskStatus status)
        {
            if (Monitor.TryEnter(SyncObject, 0))
            {
                mStatus = status;
                Monitor.Exit(SyncObject);
                return true;
            }
            else
                return false;
        }

        internal void Exit()
        {
            Monitor.Exit(SyncObject);
        }

        #endregion

        /*////////////////////////////////////////////////////////////////////////////////////////////////////*/

        #region Class Constructor

        internal Task()
        {
            SyncObject = new object();
        }

        public Task(Action<object> callBackTarget)
            : this(callBackTarget, null) { }

        public Task(Action<object> callBackTarget, object state) 
            : this(callBackTarget, state, TaskCreationOptions.None) { }

        public Task(Action<object> callBackTarget, object state, TaskCreationOptions options)
        {
            SyncObject = new object();
            mType = TaskType.CallbackFunction;

            mState = state;
            mCallBackTarget = callBackTarget;
            mFinished = new ManualResetEvent(false);
        }

        #endregion

        /*////////////////////////////////////////////////////////////////////////////////////////////////////*/

        /// <summary>
        /// Add new tasks
        /// </summary>
        /// <param name="tasks"></param>
        internal void AddChildren(List<Task> tasks)
        {
            mChildren.AddRange(tasks);
        }

        /// <summary>
        /// mark all Children canceld tasks.
        /// </summary>
        internal void NotifyChildrenForCancellation()
        {
            if (mChildren == null) return;

            for (int i = 0; i < mChildren.Count; i++)
                mChildren[i].Status = TaskStatus.Canceled;
        }

        /// <summary>
        /// Execute this task.
        /// </summary>
        internal virtual bool Execute()
        {
            if (mStatus == TaskStatus.Started || mStatus == TaskStatus.Canceled) return false;
            mStatus = TaskStatus.Started;

            if (mType == TaskType.CallbackFunction)
            {
                CallBackTarget(State);
            }
            
            return true;
        }

        internal virtual void MarkAsFinished()
        {
            mFinished.Set();
        }

        /// <summary>
        /// Choice Identity for this task
        /// </summary>
        internal void ChoiceId(string parentTaskId)
        {
            if (mType == TaskType.ForFunction) return;

            if (string.IsNullOrEmpty(parentTaskId))
                mIdentity = NativeMethod.GetTickCount().ToString();// + RandomEx.NextDouble().ToString();
            else
                mIdentity = parentTaskId + "." + NativeMethod.GetTickCount().ToString();// +new Random().NextDouble().ToString();
        }

        /// <summary>
        /// Return a string that represent this Task instance
        /// </summary>
        public override string ToString()
        {
            return mIdentity;
        }

    }
}
